/* Copyright (C) 2008  Romolo Camplani, Marco Fortunato, Marco Marelli, Guido Rota, Fabio A. Schreiber et al.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.dei.perla.parser.expressions;

import java.lang.reflect.InvocationTargetException;

/**
 * Classe costantante Vettore
 * @author Stefano Vettor
 */
public class ConstantVectorFloat extends ConstantUserDefined {
	private double vectorValue [];
	

	public ConstantVectorFloat(String alias, String initializationString) throws ConstantCreationException {
		super(alias, initializationString);
		initializationString = initializationString.replace(" ", "");
		String vector[] = initializationString.split(",");
		vectorValue = new double[vector.length];
		for (int i = 0; i < vector.length; i++) {
			try {
				vectorValue[i] = Double.parseDouble(vector[i]);
			}
			catch (NumberFormatException parException) {
				throw new ConstantCreationException();
			}
		}
	}
	
	public ConstantVectorFloat(double[] par) {
		super("ConstantVector", par.toString());
		vectorValue = par;
	}
	
	public double[] getValueVec() {
		return this.vectorValue;
	}
	
	public Integer getVectorSize() {
		return new Integer(this.vectorValue.length);
	}
	
	public Constant multiplication(Constant parConst) throws ConstantCastException {
		if ((parConst.getClass() == ConstantInteger.class) || (parConst.getClass() == ConstantFloat.class)) {
			double[] parArray = new double[vectorValue.length];
			for (int i = 0; i < vectorValue.length; i++) {
				parArray[i] = parConst.getValueFloat() * vectorValue[i];
			}
			return new ConstantVectorFloat(parArray);
		}
		else
			return new ConstantNull();
	}
	
	public static Class<? extends Object> multiplicationResultType(Class<? extends Constant> parConst) throws OperationNotSupportedException {
		if ((parConst == ConstantInteger.class) || (parConst == ConstantFloat.class))
			return ConstantVectorFloat.class;
		else if (parConst == ConstantNull.class)
			return ConstantNull.class;
		else if (parConst.getSuperclass() == ConstantUserDefined.class) {
			try {
				return (Class<? extends Object>) parConst.getClass().getMethod("multiplicationInverseResultType").invoke(parConst, ConstantVectorFloat.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new OperationNotSupportedException("Operation * not supported with " + parConst.toString());
			}
		}
		else
			throw new OperationNotSupportedException("Operation * not supported with " + parConst.toString());
	}
	
	public Constant subtraction(Constant parConst) throws ConstantCastException, OperationNotSupportedException {
		if (parConst.getClass() == ConstantVectorFloat.class) {
			try {
				if (((Integer) parConst.getClass().getMethod("getVectorSize").invoke(parConst, new Object[0])).intValue() != this.vectorValue.length) {
					throw new ConstantRuntimeException("Wrong vector size");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			double[] secArray;
			try {
				secArray = (double []) parConst.getClass().getMethod("getValueVec").invoke(parConst, new Object[0]);
			} catch (Exception e) {
				secArray = null;
				e.printStackTrace();
			}
			double[] parArray = new double[vectorValue.length];
			for (int i = 0; i < vectorValue.length; i++) {
				parArray[i] = vectorValue[i] - secArray[i];
			}
			return new ConstantVectorFloat(parArray);
		}
		else if (parConst.isUserDefined())
			return parConst.subtractionInverse(this);
		else
			return new ConstantNull();
	}
	
	public static Class<? extends Object> subtractionResultType(Class<? extends Constant> parConst) throws OperationNotSupportedException {
		if (parConst == ConstantVectorFloat.class)
			return ConstantVectorFloat.class;
		else if (parConst == ConstantNull.class)
			return ConstantNull.class;
		else if (parConst.getSuperclass() == ConstantUserDefined.class) {
			try {
				return (Class<? extends Object>) parConst.getClass().getMethod("subtractionInverseResultType").invoke(parConst, ConstantVectorFloat.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new OperationNotSupportedException("Operation - not supported with " + parConst.toString());
			}
		}
		else
			throw new OperationNotSupportedException("Operation - not supported with " + parConst.toString());
	}
	
	public Constant addition(Constant parConst) throws ConstantCastException, OperationNotSupportedException {
		if (parConst.getClass() == ConstantVectorFloat.class) {
			try {
				if (((Integer) parConst.getClass().getMethod("getVectorSize").invoke(parConst, new Object [0])).intValue() != this.vectorValue.length) {
					throw new ConstantRuntimeException("Wrong vector size");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			double[] secArray;
			try {
				secArray = (double []) parConst.getClass().getMethod("getValueVec").invoke(parConst, new Object [0]);
			} catch (Exception e) {
				secArray = null;
				e.printStackTrace();
			}
			double[] parArray = new double[vectorValue.length];
			for (int i = 0; i < vectorValue.length; i++) {
				parArray[i] = vectorValue[i] + secArray[i];
			}
			return new ConstantVectorFloat(parArray);
		}
		else if (parConst.isUserDefined())
			return parConst.additionInverse(this);
		else
			return new ConstantNull();
	}
	
	public static Class<? extends Object> additionResultType(Class<? extends Constant> parConst) throws OperationNotSupportedException {
		if (parConst == ConstantVectorFloat.class)
			return ConstantVectorFloat.class;
		else if (parConst == ConstantNull.class)
			return ConstantNull.class;
		else if (parConst.getSuperclass() == ConstantUserDefined.class) {
			try {
				return (Class<? extends Object>) parConst.getClass().getMethod("additionInverseResultType").invoke(parConst, ConstantVectorFloat.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new OperationNotSupportedException("Operation + not supported with " + parConst.toString());
			}
		}
		else
			throw new OperationNotSupportedException("Operation + not supported with " + parConst.toString());
	}
	
	public Constant multiplicationInverse(Constant parConst) throws ConstantCastException {
		if ((parConst.getClass() == ConstantInteger.class) || (parConst.getClass() == ConstantFloat.class)) {
			double[] parArray = new double[vectorValue.length];
			for (int i = 0; i < vectorValue.length; i++) {
				parArray[i] = parConst.getValueFloat() * vectorValue[i];
			}
			return new ConstantVectorFloat(parArray);
		}
		else
			return new ConstantNull();
	}
	
	public static Class<? extends Object> multiplicationInverseResultType(Class<? extends Constant> parConst) throws OperationNotSupportedException {
		if ((parConst == ConstantInteger.class) || (parConst == ConstantFloat.class))
			return ConstantVectorFloat.class;
		else if (parConst == ConstantNull.class)
			return ConstantNull.class;
		else if (parConst.getSuperclass() == ConstantUserDefined.class) {
			try {
				return (Class<? extends Object>) parConst.getClass().getMethod("multiplicationResultType").invoke(parConst, ConstantVectorFloat.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new OperationNotSupportedException("Operation * not supported with " + parConst.toString());
			}
		}
		else
			throw new OperationNotSupportedException("Operation * not supported with " + parConst.toString());
	}
	
	public Constant subtractionInverse(Constant parConst) throws ConstantCastException, OperationNotSupportedException {
		if (parConst.getClass() == ConstantVectorFloat.class) {
			try {
				if (((Integer) parConst.getClass().getMethod("getVectorSize").invoke(parConst, new Object [0])).intValue() != this.vectorValue.length) {
					throw new ConstantRuntimeException("Wrong vector size");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			double[] secArray;
			try {
				secArray = (double []) parConst.getClass().getMethod("getValueVec").invoke(parConst, new Object [0]);
			} catch (Exception e) {
				secArray = null;
				e.printStackTrace();
			}
			double[] parArray = new double[vectorValue.length];
			for (int i = 0; i < vectorValue.length; i++) {
				parArray[i] = secArray[i] - vectorValue[i];
			}
			return new ConstantVectorFloat(parArray);
		}
		else if (parConst.isUserDefined())
			return parConst.subtraction(this);
		else
			return new ConstantNull();
	}
	
	public static Class<? extends Object> subtractionInverseResultType(Class<? extends Constant> parConst) throws OperationNotSupportedException {
		if (parConst == ConstantVectorFloat.class)
			return ConstantVectorFloat.class;
		else if (parConst == ConstantNull.class)
			return ConstantNull.class;
		else if (parConst.getSuperclass() == ConstantUserDefined.class) {
			try {
				return (Class<? extends Object>) parConst.getClass().getMethod("subtractionResultType").invoke(parConst, ConstantVectorFloat.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new OperationNotSupportedException("Operation - not supported with " + parConst.toString());
			}
		}
		else
			throw new OperationNotSupportedException("Operation - not supported with " + parConst.toString());
	}
	
	public Constant additionInverse(Constant parConst) throws ConstantCastException, OperationNotSupportedException {
		if (parConst.getClass() == ConstantVectorFloat.class) {
			try {
				if (((Integer) parConst.getClass().getMethod("getVectorSize").invoke(parConst, new Object [0])).intValue() != this.vectorValue.length) {
					throw new ConstantRuntimeException("Wrong vector size");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			double[] secArray;
			try {
				secArray = (double []) parConst.getClass().getMethod("getValueVec").invoke(parConst, new Object [0]);
			} catch (Exception e) {
				secArray = null;
				e.printStackTrace();
			}
			double[] parArray = new double[vectorValue.length];
			for (int i = 0; i < vectorValue.length; i++) {
				parArray[i] = secArray[i] + vectorValue[i];
			}
			return new ConstantVectorFloat(parArray);
		}
		else if (parConst.isUserDefined())
			return parConst.addition(this);
		else
			return new ConstantNull();
	}
	
	public static Class<? extends Object> additionInverseResultType(Class<? extends Constant> parConst) throws OperationNotSupportedException {
		if (parConst == ConstantVectorFloat.class )
			return ConstantVectorFloat.class;
		else if (parConst == ConstantNull.class)
			return ConstantNull.class;
		else if (parConst.getSuperclass() == ConstantUserDefined.class) {
			try {
				return (Class<? extends Object>) parConst.getClass().getMethod("additionResultType").invoke(parConst, ConstantVectorFloat.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new OperationNotSupportedException("Operation + not supported with " + parConst.toString());
			}
		}
		else
			throw new OperationNotSupportedException("Operation + not supported with " + parConst.toString());
	}
	
	public String toString() {
		String ret = "[";
		for (int i = 0; i < vectorValue.length; i++) {
			ret += " " + vectorValue[i];
		}
		ret += "]";
		return ret;
	}
}
